package com.panda.git;

import com.panda.pojo.Component;
import com.panda.pojo.Context;
import com.panda.pojo.Pr;
import com.panda.pojo.Service;

import java.io.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/*

    从仓库中拉取到Pr包,然后将拉取到的内容缓存在本地

    将Pr包中服务以及组件添加group和root前缀放入context

    如果指定了其命名空间,将会再使用命名空间另起一份放入context中

 */
public class PullUtils {


    public static boolean pull(Context context, String group, String root, String version, String namespace) {

        Pr pr;
        //首先尝试能够从本地获取到Pr对象

        pr = readFromLocal(context, group, root, version);

        if (pr == null) {

            //从仓库获取
            pr = NetworkUtils.pull(group, root, version);

            if (pr != null) {

                //将pr缓存在本地
                writeToLocal(context, group, root, version, pr);

            }

        }

        //对pr进行处理

        if (pr != null) {

            Map<String, Component> componentMap = pr.getComponentMap();

            Map<String, Component> contextComponentMap = context.getComponentMap();

            String pre = "@" + group + "/" + root + "/" + version + "/";
            String svPre = ("__" + group + "_" + root + "_" + version + "_").replace(".", "_");


            Set<String> services = pr.getServiceMap().keySet();

            //将组件放到上下文中
            for (String name : componentMap.keySet()) {

                Component component = componentMap.get(name);
                String s = pre + name;
                context.addComponentName(s);
                contextComponentMap.put(s, component);
                component.setContext(context);

                if (namespace != null) {
                    s = namespace + "/" + name;
                    context.addComponentName(s);
                    contextComponentMap.put(s, component);
                }

                Set<String> dependencies = component.getScope().getDependencies();

                Set<String> nds = new HashSet<>();

                //修改依赖
                for (String dependency : dependencies) {

                    if (services.contains(dependency)) {
                        nds.add(svPre + dependency);
                    } else {
                        nds.add(dependency);
                    }

                }

                component.getScope().setDependencies(nds);

            }

            Map<String, Service> prServiceMap = pr.getServiceMap();

            Map<String, Service> serviceMap = context.getServiceMap();

            for (String name : prServiceMap.keySet()) {

                Service service = prServiceMap.get(name);

                String s = svPre + name;

                service.setName(svPre + service.getName());

                serviceMap.put(s, service);

                if (namespace != null) {
                    s = namespace + "_" + name;
                    serviceMap.put(s, service);
                }

                //服务的依赖
                Set<String> dependencies = service.getDependencies();

                if (dependencies != null) {

                    Set<String> nds = new HashSet<>();

                    //修改依赖
                    for (String dependency : dependencies) {

                        if (services.contains(dependency)) {
                            String t = svPre + dependency;

                            nds.add(t);

                            //对服务中的脚本进行替换

                            String body = service.getBody();

                            //只对库中含有的服务依赖进行替换

                            //对服务的文本替换
                            body = body.replaceAll("((?<=([+-/*=%!({\\[><&|^;:\n])|^|(in)) *)" + dependency + "((?= *[}.\n])|$)", t);
                            body = body.replaceAll("\\?[ \n]*" + dependency + "[ \n]*:", "?" + t + ":");

                            service.setBody(body);

                        } else {
                            nds.add(dependency);
                        }


                    }

                    service.setDependencies(nds);
                }

            }

            return true;
        }

        return false;


    }

    private static void writeToLocal(Context context, String group, String root, String version, Pr pr) {

        String dc = (String) context.getConfig().get("dir.cache");

        if (dc == null) {
            throw new RuntimeException("没有文件缓存路径");
        }

        String path = dc + "/" + group + "_" + root + "_" + version;

        //创建对象输出
        ObjectOutputStream objectOutputStream = null;
        try {
            objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File(path)));
            objectOutputStream.writeObject(pr);
            objectOutputStream.close();
        } catch (Exception e) {

            if (objectOutputStream != null) {
                try {
                    objectOutputStream.close();
                } catch (IOException e1) {
                    throw new RuntimeException(e1);
                }
            }

        }


    }

    private static Pr readFromLocal(Context context, String group, String root, String version) {

        String dc = (String) context.getConfig().get("dir.cache");


        if (dc == null) {
            throw new RuntimeException("没有文件缓存路径");
        }

        return readFromLocal(dc + "/" + group + "_" + root + "_" + version);

    }

    private static Pr readFromLocal(String path) {
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(new FileInputStream(new File(path)));
            Pr pr = (Pr) objectInputStream.readObject();
            objectInputStream.close();
            return pr;
        } catch (Exception e) {
            if (objectInputStream != null) {
                try {
                    objectInputStream.close();
                } catch (IOException e1) {
                    throw new RuntimeException(e1);
                }
            }
            return null;
        }

    }

}
